<?php
/**
 * Created by PhpStorm
 * User: 龍zero
 * Date: 2022-04-10
 * Time: 16:28
 */
declare(strict_types=1);

namespace  App\Service;

use App\Exception\AuthenticationException;
use App\Exception\TokenException;
use App\Lib\Tools\LocalUser;
use App\Model\LinUser as User;
use App\Service\Contract\ITokenProviderService;
use Firebase\JWT\JWT;
use function Hyperf\Support\env;

class TokenProvideService implements  ITokenProviderService
{
    private $accessKey;

    private $refreshKey;

    private $iss;

    public function __construct($accessKey,$refreshKey,$iss='woshidashuaige-zero')
    {
        $this->accessKey = $accessKey;
        $this->refreshKey = $refreshKey;
        $this->iss = $iss;
    }

    public function getToken($user):array
    {
        $accessToken = $this->createAccessToken($user);
        $refreshToken = $this->createRefreshToken($user);
        return [
            'access_token' => $accessToken,
            'refresh_token' => $refreshToken
        ];
    }

    public function refreshToken()
    {
        try {
            $user = LocalUser::getLocalUser();
            $accessToken = $this->createAccessToken($user);
            $refreshToken = $this->createRefreshToken($user);
        } catch (TokenException $ex) {
            throw new TokenException(['code' => $ex->code]);
        }
        return [
            'access_token' => $accessToken,
            'refresh_token' => $refreshToken
        ];
    }

    private  function createAccessToken($user)
    {
//        $key = config("jwt.guards.{$this->guard}.access");
        if(env('APP_ENV') != 'dev'){
            $time = 7200;
        }else{
            $time = 86400;
        }
        $key = $this->accessKey;
        $payload = [
            'iss' => 'woshidashuaige-zero', //签发者
            'iat' => time(), //什么时候签发的
            'exp' => time() + $time, //过期时间
            'user' => ['id' => $user->id],
        ];
        $token = JWT::encode($payload, $key);
        return $token;

    }

    private  function createRefreshToken($user)
    {
//        $key = config("jwt.guards.{$this->guard}.refresh");
        if(env('APP_ENV') != 'dev'){
            $time = 86400;
        }else{
            $time = 86400 * 7;
        }
        $key = $this->refreshKey;
        $payload = [
            'iss' => 'woshidashuaige-zero', //签发者
            'iat' => time(), //什么时候签发的
            'exp' => time() + $time,
            'user' => ['id' => $user->id],
        ];
        $token = JWT::encode($payload, $key);
        return $token;
    }


    /**
     * @return mixed
     * @throws TokenException
     * @param string $tokenType
     * @return mixed
     */
    public function getCurrentUID($tokenType='access')
    {
        $uid = $this->getCurrentTokenVar('id',$tokenType);
        return $uid;
    }


    /**
     * @param $key
     * @param string $tokenType
     * @return mixed
     * @throws TokenException
     */
    private  function getCurrentTokenVar($key, $tokenType)
    {
        $request = request();
        $authorization = $request->getHeaderLine("authorization");

        if (!$authorization) {
            throw new AuthenticationException(10000);
        }

        list($type, $token) = explode(' ', $authorization);

        if ($type !== 'Bearer') throw new TokenException(10013);
        if (!$token || $token === 'undefined') {
            throw new TokenException(20004);
        }
        if($tokenType == 'access'){
            $secretKey = $this->accessKey;
        }else{
            $secretKey =  $this->refreshKey;
        }
        try {
            $jwt = (array)JWT::decode($token, $secretKey, ['HS256']);
        } catch (\Firebase\JWT\SignatureInvalidException $e) {  //签名不正确
            if($tokenType == 'access'){
                throw new TokenException(['code' => 10041]);
            }else{
                throw new TokenException(['code' => 10042]);
            }
        } catch (\Firebase\JWT\BeforeValidException $e) {  // 签名在某个时间点之后才能用
            throw new TokenException(['code' => 10050]);
        } catch (\Firebase\JWT\ExpiredException $e) {  // token过期
            if($tokenType == 'access'){
                throw new TokenException(['code' => 10051]);
            }else{
                throw new TokenException(['code' => 10052]);
            }
        } catch (\Exception $e) {  //其他错误
            throw new TokenException(['code'=> 10040]);
        }
        if (property_exists($jwt['user'],$key)) {
            return $jwt['user']->$key;
        } else {
            throw new TokenException(['code' => 10041]);
        }

    }
}
